#ifndef SWEEPLINE_H
#define SWEEPLINE_H

#include "main.h"
#include "bintree.h"
#include "EventQueue.h"

struct Point;

class SweepLine {
	vector<SLseg*> SLsegmenty;
    CBinTree Tree;

public:
	SweepLine() { Tree = *(new CBinTree()); }
    ~SweepLine(void){ Tree.freetree(); }
                
    SLseg*   add			(Event*);
    SLseg*   find			(Event*);
    void     intersect		(SLseg*, SLseg*, EventQueue*);
    void     remove			(SLseg*);
	Point*	intersect_point (Point* p1, Point *p2, Point *p3, Point *p4);
	bool contains(set<Point*>* s, Point * p);
};
//prida event do sweepline tak, ze vytvori novy SLseg
SLseg* SweepLine::add(Event* E)
{
    //prirad do segmentu cislo hrany
    SLseg* s = new SLseg(E->edge);
    //pridavame => LEFT edge event
    //zistime, ktory bod je lavy
	if (xyorder(&(E->eV[0]), E->another_vertex) < 0)  
	{ // determine which is leftmost
        s->lP = E->eV[0];
        s->rP = *E->another_vertex;
    }
    else 
	{
        s->rP = E->eV[0];
        s->lP = *E->another_vertex; //E->eV[1];
    }

    s->above = (SLseg*)0;
    s->below = (SLseg*)0;

    Tnode* nd = Tree.insert(s);
    Tnode* nx = Tree.next(nd);
    Tnode* np = Tree.prev(nd);
	//ak existuje dalsi uzol
    if (nx != (Tnode*)0) 
	{
        s->above = (SLseg*)nx->val;
        s->above->below = s;
    }
	//ak existuje predchadzajuci uzol
    if (np != (Tnode*)0) 
	{
        s->below = (SLseg*)np->val;
        s->below->above = s;
    }
    return s;
}
//najde segment v strome
SLseg* SweepLine::find(Event* E)
{
	SLseg* s = new SLseg(E->edge);
    s->above = (SLseg*)0;
    s->below = (SLseg*)0;

    Tnode* nd = Tree.find(s);
    delete s;
    if (nd == (Tnode*)0) return (SLseg*)0;

    return (SLseg*)nd->val;
}
void SweepLine::remove(SLseg* s)
{
	Tree.Remove_public(s);
	return;
}
void SweepLine::intersect(SLseg* s1, SLseg* s2, EventQueue* Eq)
{
	//ak neexistuju, skonci - nestava sa
	if (s1 == (SLseg*)0 || s2 == (SLseg*)0) return;     

#ifdef DEBUG
	cout << "Porovnavam segmenty hran " << s1->edge << " a " << s2->edge << endl;
#endif

	//rovnaky segment - nestava sa
	if (s1->edge == s2->edge) return;					 

    //test existencie priesecniku
    float lsign, rsign;
    lsign = isLeft(s1->lP, s1->rP, s2->lP);    // poloha laveho bodu z s2 vzhladom k segmentu s1
    rsign = isLeft(s1->lP, s1->rP, s2->rP);    // poloha praveho bodu z s2 vzhladom k segmentu s1
    if (lsign * rsign > 0) return ;	// ak oba lezia na jednej strane, nemozu sa pretinat
	if (lsign == 0 && rsign == 0) //ak lezia na priamke
	{
		if (overlap(s1, s2)) //zisti ci sa neprekryvaju
		{
			cout << "Prekryvajuce sa segmenty ciar " << s1->edge << " a " << s2->edge << endl;
			return;
		}
	}
    lsign = isLeft(s2->lP, s2->rP, s1->lP);    // ^^ 
    rsign = isLeft(s2->lP, s2->rP, s1->rP);    // ^^ 
    if (lsign * rsign > 0) return;  // ^^

	//existuje priesecnik
	Point* intersectPoint = intersect_point(&s1->lP, &s1->rP, &s2->lP, &s2->rP);	
	//odstran skarede desatinne miesta, lamoidne spravene
	intersectPoint->Sanitize();

	//skus pretnut aj dalsie segmenty
	if (s1->above == s2)
		Eq->add(intersectPoint, s2, s1);
	else
		Eq->add(intersectPoint, s1, s2);
}
Point* SweepLine::intersect_point (Point* p1, Point *p2, Point *p3, Point *p4)
{
	//mudry vzorec na ratanie bodu, kde sa tieto 2 priamky pretnu
	float f = (
		(((p4->x - p3->x)*(p1->y - p3->y)) - ((p4->y - p3->y)*(p1->x - p3->x))) /
	//----------------------------------------------------------------------------
	    (((p4->y - p3->y)*(p2->x - p1->x)) - ((p4->x - p3->x)*(p2->y - p1->y)))
		);
	return new Point(p1->x + f*(p2->x - p1->x),p1->y + f*(p2->y - p1->y)); 
}

#endif
